﻿using System.Text;
using RpcCentral.Collect.Model;
using RpcCentral.Common;
using RpcCentral.DAL;
using RpcCentral.Model;
using RpcHelper;
using RpcModel;

namespace RpcCentral.Collect.Helper
{
    internal class TransmitHelper : ITransmitHelper
    {
        private static readonly long _HashCodeSum = 4294967295;
        private static readonly int _ZoneIndexSum = 79;

        private IServerTransmitConfigDAL _TransmitConfig;
        private IRemoteServerGroupDAL _ServerGroup;

        public TransmitHelper(IServerTransmitConfigDAL transmitConfig, IRemoteServerGroupDAL serverGroup)
        {
            _TransmitConfig = transmitConfig;
            _ServerGroup = serverGroup;
        }

        private long[] _ServerId;
        public bool GetTransmits(long rpcMerId, long systemType, ref string ver, out Transmit[] transmits)
        {
            ServerTransmitConfig[] configs = this._TransmitConfig.Gets(systemType, rpcMerId);
            if (configs.Length == 0)
            {
                transmits = Array.Empty<Transmit>();
                return ver == string.Empty;
            }
            StringBuilder str = new StringBuilder();
            configs.ForEach(a =>
            {
                str.Append(a.Id);
                str.Append(",");
                str.Append(a.VerNum);
            });
            if (configs.IsExists(a => a.SeverId == 0))
            {
                str.Append("_");
                _ServerId = _ServerGroup.GetRemoteServerId(rpcMerId, systemType);
                str.AppendJoin(",", _ServerId);
            }
            string verVal = str.ToString().GetMd5();
            if (verVal == ver)
            {
                transmits = null;
                return false;
            }
            List<Transmit> list = new List<Transmit>();
            configs.ForEach(a =>
            {
                if (a.SeverId == 0)
                {
                    this._AutoGenerate(list, a);
                }
                else
                {
                    a.TransmitConfig.ForEach(c =>
                    {
                        c.Range.ForEach(b =>
                        {
                            if (b.BeginRange == b.EndRanage)
                            {
                                b.IsFixed = true;
                            }
                        });
                        list.Add(new Transmit
                        {
                            Range = c.Range.ToArray(),
                            Scheme = a.Scheme,
                            TransmitType = a.TransmitType,
                            Value = c.Value,
                            SeverId = a.SeverId,
                            Sort = 100
                        });
                    });
                }
            });
            transmits = list.OrderByDescending(a => a.Sort).Distinct().ToArray();
            ver = verVal;
            return true;
        }

        private void _InitHashCode(List<Transmit> transmits, ServerTransmitConfig config)
        {
            if (_ServerId.Length == 1)
            {
                transmits.Add(new Transmit
                {
                    Range = new TransmitRange[]
                    {
                        new TransmitRange
                        {
                            BeginRange = int.MinValue,
                            EndRanage = int.MaxValue
                        }
                    },
                    Scheme = config.Scheme,
                    TransmitType = config.TransmitType,
                    SeverId = _ServerId[0]
                });
            }
            else
            {
                _InitTransmit(_HashCodeSum, int.MinValue, (long)int.MaxValue + 1, transmits, config);
            }
        }
        private void _InitTransmit(long sum, long begin, long max, List<Transmit> transmits, ServerTransmitConfig config)
        {
            int num = (int)(_ServerId.Length * RpcContralConfig.TransmitScale);
            long size = sum / num;
            int len = _ServerId.Length;
            long endId = _ServerId[_ServerId.Length - 1];
            Dictionary<long, List<TransmitRange>> dics = new Dictionary<long, List<TransmitRange>>();
            for (int k = 0; k < num; k++)
            {
                long i = _ServerId[k % len];
                long end = i == endId ? max : begin + size;
                if (dics.TryGetValue(i, out List<TransmitRange> ranges))
                {
                    ranges.Add(new TransmitRange
                    {
                        BeginRange = begin,
                        EndRanage = end
                    });
                }
                else
                {
                    ranges = new List<TransmitRange> {
                      new TransmitRange
                      {
                        BeginRange=begin,
                        EndRanage=end
                      }
                    };
                    dics.Add(i, ranges);
                }
                begin = end;
            }
            foreach (KeyValuePair<long, List<TransmitRange>> i in dics)
            {
                transmits.Add(new Transmit
                {
                    Range = i.Value.ToArray(),
                    Scheme = config.Scheme,
                    SeverId = config.SeverId,
                    TransmitType = config.TransmitType
                });
            }
        }
        private void _InitZoneIndex(List<Transmit> transmits, ServerTransmitConfig config)
        {
            if (this._ServerId.Length == 1)
            {
                transmits.Add(new Transmit
                {
                    Range = new TransmitRange[]
                    {
                            new TransmitRange
                            {
                                BeginRange=48,
                                EndRanage=128,
                                IsFixed=false
                            }
                    },
                    Scheme = config.Scheme,
                    TransmitType = config.TransmitType,
                    SeverId = this._ServerId[0]
                });
            }
            else
            {
                _InitTransmit(_ZoneIndexSum, 48, 128, transmits, config);
            }
        }


        private void _AutoGenerate(List<Transmit> transmits, ServerTransmitConfig config)
        {
            if (config.TransmitType == TransmitType.HashCode)
            {
                _InitHashCode(transmits, config);
            }
            else if (config.TransmitType == TransmitType.ZoneIndex)
            {
                _InitZoneIndex(transmits, config);
            }
        }
    }
}
